package com.wangsd.web.coupon.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wangsd.common.component.WxComponentService;
import com.wangsd.common.component.WxjavaService;
import com.wangsd.common.config.WxOpenProperties;
import com.wangsd.web.MyController;
import com.wangsd.web.coupon.entity.Member;
import com.wangsd.web.coupon.entity.WxComponentAuth;
import com.wangsd.web.coupon.service.CompanyService;
import com.wangsd.web.coupon.service.CouponService;
import com.wangsd.web.coupon.service.MemberService;
import com.wangsd.web.coupon.service.WxComponentAuthService;
import com.wangsd.web.sys.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizationInfo;
import me.chanjar.weixin.open.bean.auth.WxOpenAuthorizerInfo;
import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage;
import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult;
import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信开放平台-网站应用
 */
@RequestMapping("/notify")
@RestController
@Slf4j
public class WxCallBackController extends MyController {
    @Autowired
    WxComponentService wxComponentService;
    @Autowired
    WxjavaService wxjavaService;
    @Autowired
    SysUserService userService;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    WxOpenProperties properties;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    CompanyService companyService;
    @Autowired
    WxComponentAuthService wxComponentAuthService;
    @Autowired
    MemberService memberService;
    @Autowired
    CouponService couponService;

    /**
     * （第三方平台）代公众号网页授权回调
     *
     * @param appid
     * @param code
     * @param state      1微信小程序授权服务商，2普通授权
     * @param from
     * @param miniOpenid 小程序网页授权服务商为了发优惠券
     */
    @RequestMapping("/authorizeCallbak")
    public void authorizeCallbak(String appid, String code, String state, String from, String miniOpenid) {
        log.debug("回调授权：" + miniOpenid);
        try {
            WxMpOAuth2AccessToken accessToken = wxComponentService.getWxOpenComponentService().oauth2getAccessToken(appid, code);
            String openid = accessToken.getOpenId();
            if ("1".equals(state)) {
                stringRedisTemplate.opsForValue().set(miniOpenid, openid);

                //授权成功保存用户信息，防止用户此时还没有授权头像或者手机号码的时候领取优惠券
                Member member = new Member();
                member.setMiniOpenid(miniOpenid);
                member.setPayOpenid(openid);
                memberService.register(member);
            } else {
                if (from != null) {
                    if (from.contains("?")) {
                        response.sendRedirect(from + "&openid=" + openid + "&appid=" + appid);
                    } else {
                        response.sendRedirect(from + "?openid=" + openid + "&appid=" + appid);
                    }
                }
            }
        } catch (IOException e) {
            log.error("IOException",e);
        } catch (WxErrorException e) {
            log.error("WxErrorException",e);
        }
    }

    /**
     * 小程序回调通知
     *
     * @param appid      微信公众号appid
     * @param code
     * @param state      1小程序对应openid
     * @param openid       支付openid 对应以前openid2
     */
    @RequestMapping("/memberAuthCallBack")
    public void memberAuthCallBack(String appid, String code, String state, String openid) {
        log.debug("小程序回调通知：appid={},code={},state={},openid={}" ,appid,code,state,openid);
        stringRedisTemplate.opsForValue().set(state, openid);
        //授权成功保存用户信息，防止用户此时还没有授权头像或者手机号码的时候领取优惠券
        Member member = new Member();
        member.setMiniOpenid(state);
        member.setPayOpenid(openid);
        memberService.register(member);
    }

    /**
     * 微信云支付回调
     *
     * @param body
     */
    @RequestMapping("/cloudCallBack")
    public void cloudCallBack(@RequestBody String body) {
        log.info("微信云支付回调开始:"+body);
        JSONObject requestContent = JSON.parseObject(body).getJSONObject("request_content");
        //保存交易记录
        couponService.saveTrade(requestContent);

        //回复微信已收到回调
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> responseContent = new HashMap<>();
        responseContent.put("status", 0);
        result.put("response_content", responseContent);
        try {
            response.getOutputStream().print(JSONObject.toJSONString(result));
        } catch (IOException e) {
            log.error("IOException",e);
        }
        log.info("微信云支付回调完成！！！！！！！！！");
    }

    /**
     * 授权成功回调地址(公众号授权给第三方平台)
     *
     * @param auth_code
     */
    @RequestMapping("authCallback/{businessServiceId}")
    public void authCallback(String auth_code, @PathVariable String businessServiceId) {
        log.debug("-----authCallback-----" + businessServiceId);
        try {
            WxOpenQueryAuthResult result = wxComponentService.getWxOpenComponentService().getQueryAuth(auth_code);
            WxOpenAuthorizationInfo authorizationInfo = result.getAuthorizationInfo();

            String authorizer_appid = authorizationInfo.getAuthorizerAppid();
            String authorizer_access_token = authorizationInfo.getAuthorizerAccessToken();
            String authorizer_refresh_token = authorizationInfo.getAuthorizerRefreshToken();
            String func_info = JSON.toJSONString(authorizationInfo.getFuncInfo());

            WxOpenAuthorizerInfoResult result2 = wxComponentService.getWxOpenComponentService().getAuthorizerInfo(authorizer_appid);
            WxOpenAuthorizerInfo authorizerInfo = result2.getAuthorizerInfo();
            String qrcode_url = authorizerInfo.getQrcodeUrl();
            String user_name = authorizerInfo.getUserName();
            String nick_name = authorizerInfo.getNickName();
            String head_img = authorizerInfo.getHeadImg();
            String principal_name = authorizerInfo.getPrincipalName();
            String alias = authorizerInfo.getAlias();
            String business_info = JSON.toJSONString(authorizerInfo.getBusinessInfo());
            Integer verify_type_info = authorizerInfo.getVerifyTypeInfo();
            Integer service_type_info = authorizerInfo.getServiceTypeInfo();

            WxComponentAuth componentAuth = new WxComponentAuth();
            componentAuth.setAuthorizerAppid(authorizer_appid);
            componentAuth.setAuthorizerAccessToken(authorizer_access_token);
            componentAuth.setAuthorizerRefreshToken(authorizer_refresh_token);
            componentAuth.setFuncInfo(func_info);
            componentAuth.setQrcodeUrl(qrcode_url);
            componentAuth.setUserName(user_name);
            componentAuth.setNickName(nick_name);
            componentAuth.setHeadImg(head_img);
            componentAuth.setPrincipalName(principal_name);
            componentAuth.setAlias(alias);
            componentAuth.setBusinessInfo(business_info);
            componentAuth.setVerifyTypeInfo(verify_type_info);
            componentAuth.setServiceTypeInfo(service_type_info);
            if (StringUtils.isNotBlank(businessServiceId) && !"null".equals(businessServiceId)) {
                componentAuth.setBusinessServiceId(Long.parseLong(businessServiceId));
            }
            wxComponentAuthService.saveWxComponent(componentAuth);
        } catch (WxErrorException e) {
            log.error("WxErrorException",e);
        }

    }

    /**
     * （第三方平台）接收取消授权通知、授权成功通知、授权更新通知，也用于接收ticket
     *
     * @param requestBody  对应POST请求的数据
     * @param timestamp    时间戳
     * @param nonce        随机数
     * @param encType      加密类型，为aes
     * @param msgSignature 消息体签名，用于验证消息体的正确性
     * @return
     */
    @RequestMapping("/receive_ticket")
    public Object receiveTicket(@RequestBody(required = false) String requestBody, @RequestParam("timestamp") String timestamp,
                                @RequestParam("nonce") String nonce, @RequestParam("signature") String signature,
                                @RequestParam(name = "encrypt_type", required = false) String encType,
                                @RequestParam(name = "msg_signature", required = false) String msgSignature) {
        log.info(
                "\n接收微信请求：[signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                signature, encType, msgSignature, timestamp, nonce, requestBody);

        if (!StringUtils.equalsIgnoreCase("aes", encType)
                || !wxComponentService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }

        // aes加密的消息
        WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody,
                wxComponentService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
        log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
        try {
            String out = wxComponentService.getWxOpenComponentService().route(inMessage);
            log.debug("\n组装回复信息：{}", out);
        } catch (WxErrorException e) {
            log.error("receive_ticket", e);
        }
        return "success";
    }

    /**
     * 接收公众号或小程序消息和事件推送
     *
     * @param requestBody
     * @param appId
     * @param signature
     * @param timestamp
     * @param nonce
     * @param openid
     * @param encType
     * @param msgSignature
     * @return
     */
    @RequestMapping("{appId}/callback")
    public Object callback(@RequestBody(required = false) String requestBody,
                           @PathVariable("appId") String appId,
                           @RequestParam("signature") String signature,
                           @RequestParam("timestamp") String timestamp,
                           @RequestParam("nonce") String nonce,
                           @RequestParam("openid") String openid,
                           @RequestParam("encrypt_type") String encType,
                           @RequestParam("msg_signature") String msgSignature) {
        log.info(
                "\n接收微信请求：[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
        if (!org.apache.commons.lang3.StringUtils.equalsIgnoreCase("aes", encType)
                || !wxComponentService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }

        String out = "";
        // aes加密的消息
        WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
                wxComponentService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
        log.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
        // 全网发布测试用例
        if (org.apache.commons.lang3.StringUtils.equalsAnyIgnoreCase(appId, "wxd101a85aa106f53e", "wx570bc396a51b8ff8")) {
            try {
                if (org.apache.commons.lang3.StringUtils.equals(inMessage.getMsgType(), "text")) {
                    if (org.apache.commons.lang3.StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) {
                        out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(
                                WxMpXmlOutMessage.TEXT().content("TESTCOMPONENT_MSG_TYPE_TEXT_callback")
                                        .fromUser(inMessage.getToUser())
                                        .toUser(inMessage.getFromUser())
                                        .build(),
                                wxComponentService.getWxOpenConfigStorage()
                        );
                    } else if (org.apache.commons.lang3.StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) {
                        String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api";
                        WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build();
                        wxComponentService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
                    }
                } else if (org.apache.commons.lang3.StringUtils.equals(inMessage.getMsgType(), "event")) {
                    WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build();
                    wxComponentService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
                }
            } catch (WxErrorException e) {
                log.error("callback", e);
            }
        } else {
            WxMpXmlOutMessage outMessage = wxComponentService.getWxOpenMessageRouter().route(inMessage, appId);
            if (outMessage != null) {
                out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, wxComponentService.getWxOpenConfigStorage());
            }
        }
        return out;
    }
}
